<?php
/**
 * Fastlib 杂项
 * 
 * $Id: functions.php 123 2010-05-30 19:55:05Z Administrator $
 * $Revision: 123 $
 * $Author: Administrator $
 * $Date: 2010-05-31 03:55:05 +0800 (星期一, 31 五月 2010) $ 
 * 本功能主要是一些系统没有不同版本间的函数差异在这里
 * 共同实现
 * 
 * @author glzaboy<glzaboy@163.com>
 * @package fastlib
 * @subpackage misc
 * @copyright 2005-2010 (c) glzaboy
 */
if (! defined ( '__FASTLIB__' )) {
	if (__DEBUG__) {
		die ( sprintf ( 'Forbidden 403 at file %s on line %d', __FILE__, __LINE__ ) );
	} else {
		die ( 'Forbidden 403' );
	}
}
if (! function_exists ( 'ftok' )) {
	function ftok($filename = "", $proj = "") {
		if (empty ( $filename ) || ! file_exists ( $filename )) {
			return - 1;
		} else {
			$filename = $filename . ( string ) $proj;
			for($key = array (); sizeof ( $key ) < strlen ( $filename ); $key [] = ord ( substr ( $filename, sizeof ( $key ), 1 ) ))
				;
			return dechex ( array_sum ( $key ) );
		}
	}
}
if (! function_exists ( 'gzdecode' ) && extension_loaded ( 'zlib' )) {
	/**
	 * Decodes a gzip compressed string
	 * 
	 * It's also useing gzinflate(substr($data,10,-8));
	 *
	 * @param string $data The data to decode, encoded by gzencode(). 
	 * @param int $maxlength The maximum length of data to decode. 
	 * @return The decoded string, or FALSE if an error occurred. 
	 */
	function gzdecode($data, $maxlength = null) {
		$xfl = $os = $extra = $comment = '';
		$filenamelen = 0;
		$len = strlen ( $data );
		if ($len < 18 || strcmp ( substr ( $data, 0, 2 ), "\x1f\x8b" )) {
			$error .= "Not in GZIP format.";
			return false; // Not GZIP format (See RFC 1952)
		}
		$method = ord ( substr ( $data, 2, 1 ) ); // Compression method
		$flags = ord ( substr ( $data, 3, 1 ) ); // Flags
		if ($flags & 31 != $flags) {
			$error .= "Reserved bits not allowed.";
			return false;
		}
		// NOTE: $mtime may be negative (PHP integer limitations)
		$mtime = unpack ( "V", substr ( $data, 4, 4 ) );
		$mtime = $mtime [1];
		$xfl .= substr ( $data, 8, 1 );
		$os .= substr ( $data, 8, 1 );
		$headerlen = 10;
		$extralen = 0;
		$extra = "";
		if ($flags & 4) {
			// 2-byte length prefixed EXTRA data in header
			if ($len - $headerlen - 2 < 8) {
				return false; // invalid
			}
			$extralen = unpack ( "v", substr ( $data, 8, 2 ) );
			$extralen = $extralen [1];
			if ($len - $headerlen - 2 - $extralen < 8) {
				return false; // invalid
			}
			$extra .= substr ( $data, 10, $extralen );
			$headerlen += 2 + $extralen;
		}
		if ($flags & 8) {
			// C-style string
			if ($len - $headerlen - 1 < 8) {
				return false; // invalid
			}
			$filenamelen = strpos ( substr ( $data, $headerlen ), chr ( 0 ) );
			if ($filenamelen === false || $len - $headerlen - $filenamelen - 1 < 8) {
				return false; // invalid
			}
			// $filename .= substr($data, $headerlen, $filenamelen);
			$headerlen += $filenamelen + 1;
		}
		$commentlen = 0;
		$comment = "";
		if ($flags & 16) {
			// C-style string COMMENT data in header
			if ($len - $headerlen - 1 < 8) {
				return false; // invalid
			}
			$commentlen = strpos ( substr ( $data, $headerlen ), chr ( 0 ) );
			if ($commentlen === false || $len - $headerlen - $commentlen - 1 < 8) {
				return false; // Invalid header format
			}
			$comment .= substr ( $data, $headerlen, $commentlen );
			$headerlen += $commentlen + 1;
		}
		$headercrc = "";
		if ($flags & 2) {
			// 2-bytes (lowest order) of CRC32 on header present
			if ($len - $headerlen - 2 < 8) {
				return false; // invalid
			}
			$calccrc = crc32 ( substr ( $data, 0, $headerlen ) ) & 0xffff;
			$headercrc = unpack ( "v", substr ( $data, $headerlen, 2 ) );
			$headercrc = $headercrc [1];
			if ($headercrc != $calccrc) {
				$error = "Header checksum failed.";
				return false; // Bad header CRC
			}
			$headerlen += 2;
		}
		// GZIP FOOTER
		$datacrc = unpack ( "V", substr ( $data, - 8, 4 ) );
		$datacrc = sprintf ( '%u', $datacrc [1] & 0xFFFFFFFF );
		$isize = unpack ( "V", substr ( $data, - 4 ) );
		$isize = $isize [1];
		// decompression:
		$bodylen = $len - $headerlen - 8;
		if ($bodylen < 1) {
			// IMPLEMENTATION BUG!
			return null;
		}
		$body = substr ( $data, $headerlen, $bodylen );
		$data = "";
		if ($bodylen > 0) {
			switch ($method) {
				case 8 :
					// Currently the only supported compression method:
					$data = gzinflate ( $body, $maxlength );
					break;
				default :
					$error = "Unknown compression method.";
					return false;
			}
		} // zero-byte body content is allowed
		// Verifiy CRC32
		$crc = sprintf ( "%u", crc32 ( $data ) );
		$crcOK = $crc == $datacrc;
		$lenOK = $isize == strlen ( $data );
		if (! $lenOK || ! $crcOK) {
			$error = ($lenOK ? '' : 'Length check FAILED. ') . ($crcOK ? '' : 'Checksum FAILED.');
			return false;
		}
		return $data;
	}
}
/**
 * 国际化语言绑定
 * 
 * 自动化语言参考
 * http://techpatterns.com/downloads/php_language_detection.php
 *
 * @param string $domain 语言包域名称
 * @return bool 返回原来绑定的域
 */
function __textdomain($domain = 'default') {
	global $l18n, $flibcfg;
	$accept_langs = array ();
	if (isset ( $_SERVER ["HTTP_ACCEPT_LANGUAGE"] )) {
		foreach ( explode ( ',', str_replace ( ' ', '', $_SERVER ["HTTP_ACCEPT_LANGUAGE"] ) ) as $lang ) {
			array_push ( $accept_langs, strtr ( substr ( $lang, 0, strcspn ( $lang, ';' ) ), array ('-' => '_' ) ) );
		}
	}
	if (isset ( $_GET ['lang'] )) {
		setGetValue ( 'lang', null, '/[^a-zA-Z0-9_-]+/', 'cookie', true );
	}
	if ($_COOKIE ['lang']) {
		array_unshift ( $accept_langs, strtr ( $_COOKIE ['lang'], array ('-' => '_' ) ) );
	}
	if (! class_exists ( 'StringReader' )) {
		require __FASTSYSTEM__ . 'driver/io/gettext.php';
	}
	$siteroot = getSiteCurrent ( true );
	//第一次查找完全匹配言语
	foreach ( $accept_langs as $v ) {
		$v = explode ( '_', $v );
		if (count ( $v ) == 1) {
			$lang = $v [0];
		} elseif (count ( $v ) == 2) {
			$lang = $v [0] . '_' . strtoupper ( $v [1] );
		}
		if (is_dir ( $siteroot . 'locale/' . $lang . '/LC_MESSAGES/' )) {
			if (! isset ( $l18n [$domain] ) && is_readable ( $siteroot . 'locale/' . $lang . '/LC_MESSAGES/' . $domain . '.mo' )) {
				$l18n [$domain] = new gettext_reader ( new StringReader ( null, $siteroot . 'locale/' . $lang . '/LC_MESSAGES/' . $domain . '.mo' ) );
			}
			if (strtoupper ( substr ( PHP_OS, 0, 3 ) ) == 'LIN') {
				setlocale ( LC_ALL, $lang . '.' . strtoupper ( $flibcfg ['charset'] ) );
			} elseif (strtoupper ( substr ( PHP_OS, 0, 3 ) ) == 'WIN') {
				if (is_readable ( $siteroot . 'locale/' . $lang . '/lang@win.' . strtoupper ( $flibcfg ['charset'] ) )) {
					$locale = file_get_contents ( $siteroot . 'locale/' . $lang . '/lang@win.' . strtoupper ( $flibcfg ['charset'] ) );
					$locale = explode ( '.', $locale );
					if (count ( $locale ) == 2) {
						$l18n [md5 ( 'lang' )] = $locale;
					}
					setlocale ( LC_ALL, $locale [0] );
				}
			} else {
				setlocale ( LC_ALL, $lang . '.' . strtoupper ( $flibcfg ['charset'] ) );
			}
			$tmp = isset ( $l18n ['currentdomain'] ) ? $l18n ['currentdomain'] : null;
			$l18n ['currentdomain'] = $domain;
			return $tmp;
		}
	}
	//查找相似语言
	$langs = array ();
	foreach ( $accept_langs as $v ) {
		$v = explode ( '_', $v );
		if (! in_array ( $v [0], $langs )) {
			array_push ( $langs, $v [0] );
		}
	}
	foreach ( $langs as $lang ) {
		if (is_dir ( $siteroot . 'locale/' . $lang . '/LC_MESSAGES/' )) {
			if (! isset ( $l18n [$domain] ) && is_readable ( $siteroot . 'locale/' . $lang . '/LC_MESSAGES/' . $domain . '.mo' )) {
				$l18n [$domain] = new gettext_reader ( new StringReader ( null, $siteroot . 'locale/' . $lang . '/LC_MESSAGES/' . $domain . '.mo' ) );
			}
			if (strtoupper ( substr ( PHP_OS, 0, 3 ) ) == 'LIN') {
				setlocale ( LC_ALL, $lang . '.' . strtoupper ( $flibcfg ['charset'] ) );
			} elseif (strtoupper ( substr ( PHP_OS, 0, 3 ) ) == 'WIN') {
				if (is_readable ( $siteroot . 'locale/' . $lang . '/lang@win.' . strtoupper ( $flibcfg ['charset'] ) )) {
					$locale = file_get_contents ( $siteroot . 'locale/' . $lang . '/lang@win.' . strtoupper ( $flibcfg ['charset'] ) );
					$locale = explode ( '.', $locale );
					if (count ( $locale ) == 2) {
						$l18n [md5 ( 'lang' )] = $locale;
					}
					setlocale ( LC_ALL, $locale [0] );
				}
			} else {
				setlocale ( LC_ALL, $lang . '.' . strtoupper ( $flibcfg ['charset'] ) );
			}
			$tmp = isset ( $l18n ['currentdomain'] ) ? $l18n ['currentdomain'] : null;
			$l18n ['currentdomain'] = $domain;
			return $tmp;
		}
	}
	return null;
}
/**
 * 本地化字符串
 *
 * @param string $text 要本地化的字符串
 * @return string 本地化后的字符串编码为站点设定的编码
 */
function __($text) {
	global $l18n, $flibcfg;
	if (isset ( $l18n [$l18n ['currentdomain']] ) && method_exists ( $l18n [$l18n ['currentdomain']], 'translate' )) {
		$text = $l18n [$l18n ['currentdomain']]->translate ( $text );
	}
	return iconv ( 'utf-8', $flibcfg ['charset'], $text );
}
/**
 * 本地化单复数字符串
 *
 * @param string $single 单数字符串
 * @param string $plural 复数字符串
 * @param int 数字
 * @return string 本地化后的字符串编码为站点设定的编码
 */
function __n($single, $plural, $number) {
	global $l18n, $flibcfg;
	if (isset ( $l18n [$l18n ['currentdomain']] ) && method_exists ( $l18n [$l18n ['currentdomain']], 'ngettext' )) {
		$text = $l18n [$l18n ['currentdomain']]->ngettext ( $single, $plural, $number );
	} else {
		if ($number != 1)
			$text = $plural;
		else
			$text = $single;
	}
	return iconv ( 'utf-8', $flibcfg ['charset'], $text );
}
/**
 * 格式化时间支持win系统
 *
 * @param string $format cookie名称
 * @param string $timestring Unix 纪元（格林威治时间 1970 年 1 月 1 日 00:00:00）到当前时间的秒数。 
 * @return mixed cookie内容
 */
function timeformat($format, $timestring = null) {
	global $l18n, $flibcfg;
	if ($timestring == null) {
		$timestamp = time ();
	} elseif (preg_match ( '/^\d{14}$/', $timestring )) {
		//format of YYYYMMDDHHMMSS? 
		$timestamp = mktime ( substr ( $timestring, 8, 2 ), substr ( $timestring, 10, 2 ), substr ( $timestring, 12, 2 ), substr ( $timestring, 4, 2 ), substr ( $timestring, 6, 2 ), substr ( $timestring, 0, 4 ) );
	} elseif (is_numeric ( $timestring )) {
		$timestamp = ( int ) $timestring;
	} else {
		$timestamp = strtotime ( $timestring );
		if ($timestamp == - 1 || $timestamp === false) {
			$timestamp = time ();
		}
	}
	if (DIRECTORY_SEPARATOR == '\\') {
		$_win_from = array ('%D', '%h', '%n', '%r', '%R', '%t', '%T' );
		$_win_to = array ('%m/%d/%y', '%b', "\n", '%I:%M:%S %p', '%H:%M', "\t", '%H:%M:%S' );
		if (strpos ( $format, '%e' ) !== false) {
			$_win_from [] = '%e';
			$_win_to [] = sprintf ( '%\' 2d', date ( 'j', $timestamp ) );
		}
		if (strpos ( $format, '%l' ) !== false) {
			$_win_from [] = '%l';
			$_win_to [] = sprintf ( '%\' 2d', date ( 'h', $timestamp ) );
		}
		$format = str_replace ( $_win_from, $_win_to, $format );
		if ($l18n [md5 ( 'lang' )]) {
			return iconv ( $l18n [md5 ( 'lang' )] [1], $flibcfg ['charset'], strftime ( $format, $timestamp ) );
		}
	}
	return strftime ( $format, $timestamp );
}
//HTTP会话相关的
/**
 * 还原成不带前缀的cookie
 *
 * @param string $name cookie名称
 * @return mixed cookie内容
 */
function fixcookie() {
	global $flibcfg;
	$cookie = array ();
	$prefixLen = strlen ( $flibcfg ['cookie_prefix'] . '_' );
	foreach ( $_COOKIE as $k => $v ) {
		if (substr ( $k, 0, $prefixLen ) == $flibcfg ['cookie_prefix'] . '_') {
			$cookie [substr ( $k, $prefixLen )] = $v;
		} else {
			$cookie [$k] = $v;
		}
	}
	unset ( $_COOKIE );
	$_COOKIE = $cookie;
	unset ( $cookie );
	return true;
}
/**
 * 开启安全session
 * 
 * 本功能一班用于多用户的虚拟主机用户，系统自动会将session的存储路径
 * 转移到用户设定的目录中，请注意目录权限问题，最好保存在一个不能在WEB
 * 访问 的目录,所有路径相对于站点根目录__SITE__，session一般用于在不同
 * 浏览器上恢复同一会话。会话有有效时间限制。
 * 
 * @param string $session_id 会话ID
 */
function fastsession($session_id = null) {
	global $flibcfg, $__SESSION;
	if ($flibcfg ['SESSION_PATH']) {
		$sess_path = getSiteCurrent ( true ) . '/' . $flibcfg ['SESSION_PATH'];
		if (! is_dir ( $sess_path )) {
			touchdir ( $sess_path );
		}
		session_save_path ( $sess_path );
	}
	if (is_string ( $session_id ) && $session_id !== null) {
		session_id ( $session_id );
	}
	ini_set ( 'url_rewriter.tags', "a=href,area=href,frame=src,form=fakeentry,fieldset=,go=href" );
	ini_set ( 'session.use_trans_sid', 1 );
	session_start ();
	$__SESSION = $_SESSION;
	if (defined ( 'SID' ) && SID != '') {
		unset ( $_GET [array_shift ( explode ( '=', SID ) )] );
		setSitecfg ( 'rewriteRule' );
	}
	setGetValue ( 'skin', 'default', '/[^a-zA-Z0-9_]+/', 'session', true );
}
/**
 * 回存本次访问前的指定SESSION
 * 
 * 比如/s/ab
 * 则会恢复$_SESSION['s']['ab']为本次会话开始的值
 *
 * @param string $sesspath session路径
 * @return bool 是否回存成功
 */
function restoresession($sesspath = '/') {
	global $__SESSION;
	if ($__SESSION) {
		if ($sesspath {0} !== '/') {
			return false;
		}
		if ($sesspath === '/') {
			$_SESSION = $__SESSION;
			return true;
		}
		$path = explode ( '/', substr ( $sesspath, 1 ) );
		eval ( '$value=$__SESSION[\'' . implode ( "']['", $path ) . '\'];' );
		eval ( '$_SESSION[\'' . implode ( "']['", $path ) . '\']=$value;' );
		return true;
	}
	return false;
}
//缓存
/**
 * 清除系统缓存
 *
 * 系统缓存是自动刷新的，增加本功能的意义在于可以
 * 立刻将缓存全部清除后重新生成
 * 界面定义主要用于显示,定义如下
 * <code>
 * array('Title'=>'cache Clean',//标题
 * 'Err'=>'System Error',//出错提示
 * 'next'=>'next',//下一步
 * 'Sucess'=>'clean Cache Sucess!',//成功后提示
 * 'DelDir'=>'delete dir %s sucess!',//目录删除成功提示
 * 'NowDEL'=>'now delete %s ...'//正在删除的目录提示
 * )
 * </code>
 * 
 * @param int $maxdelete 最大删除文件数
 * @param array $face 清除缓存界面定义 
 * @return bool 无
 */
function cleanCache($maxdelete = 100, $face = array('Title'=>'cache Clean','Err'=>'System Error','next'=>'next','Sucess'=>'clean Cache Sucess!','DelDir'=>'delete dir %s sucess!','NowDEL'=>'now delete %s ...','NotSupport'=>'Sorry, we do not support the use of mobile devices clean cache!')) {
	global $flibcfg, $sitecfg;
	loadClass ( 'message', __FILE__, __LINE__ );
	if ($sitecfg ['wml']) {
		new message ( $face ['NotSupport'], array ('value' => $face ['next'], 'action' => 'history.go(-1);' ), $face ['Title'], 0, 1, 10 );
		return false;
	}
	$siteroot = getSiteCurrent ( true );
	$hostdir = $flibcfg ['HOST'] . '_' . ($flibcfg ['PORT'] ? $flibcfg ['PORT'] : 80);
	$root = $siteroot . '.temp/cache/' . $hostdir;
	if (! is_dir ( $root )) {
		new message ( $face ['Err'], array ('value' => $face ['next'], 'action' => 'history.go(-1);' ), $face ['Title'], 0, 1, 10 );
		return true;
	}
	$d = dir ( $root );
	while ( false !== ($dir = $d->read ()) ) {
		if ($dir == '.' or $dir == '..') {
			continue;
		}
		if (is_dir ( $root . '/' . $dir )) {
			$dl = dir ( $root . '/' . $dir );
			while ( false !== ($cacheFile = $dl->read ()) ) {
				if ($cacheFile == '.' or $cacheFile == '..') {
					continue;
				}
				if (is_file ( $root . '/' . $dir . '/' . $cacheFile )) {
					unlink ( $root . '/' . $dir . '/' . $cacheFile );
					$maxdelete --;
				}
				if ($maxdelete == 0) { //正在删除
					new message ( sprintf ( $face ['NowDEL'], $dir ), array ('value' => $face ['next'], 'action' => 'window.location=window.location;' ), $face ['Title'], 0, 1, 3 );
					return true;
				}
			}
			$dl->close ();
			if ($maxdelete) {
				rmdir ( $root . '/' . $dir );
				$d->close ();
				new message ( sprintf ( $face ['DelDir'], $dir ), array ('value' => $face ['next'], 'action' => 'window.location=window.location;' ), $face ['Title'], 0, 1, 3 );
				return true;
			}
		} else {
			unlink ( $root . '/' . $dir );
		}
	}
	if ($maxdelete) {
		touch ( $root . '/index.html' );
		touch ( $root . '/index.php' );
		new message ( $face ['Sucess'], array ('value' => $face ['next'], 'action' => 'history.go(-1);' ), $face ['Title'], 0, 1, 0 );
	}
	return true;
}
/**
 * 对函数返回的结果进行散列缓存
 * 
 * 利用文件系统对函数返回的结果进行保存并返回结果，下如果调用的函数和函数的
 * 参数一致，则直接从文件中返回结果。 
 *
 * @param string $func 生成缓存的函数
 * @param array $argc 缓存函数的参数
 * @param int $exptime 缓存的时间(s秒)
 * @return mixed 缓存解码后的内容
 */
function readCache($func, $args = array(), $exptime = 86400) {
	global $flibcfg;
	$hash = serialize ( $func . serialize ( $args ) );
	$dir = '0x' . dechex ( sprintf ( "%u", crc32 ( $hash ) ) % 0xFF );
	$siteroot = getSiteCurrent ( true );
	$hostdir = $flibcfg ['HOST'] . '_' . ($flibcfg ['PORT'] ? $flibcfg ['PORT'] : 80);
	$http403 = '<?php' . PHP_EOL . ' die("HTTP 403");?>';
	touchdir ( $siteroot . '.temp' );
	touchdir ( $siteroot . '.temp/cache' );
	touchdir ( $siteroot . '.temp/cache/' . $hostdir );
	touchdir ( $siteroot . '.temp/cache/' . $hostdir . '/' . $dir );
	$file = $siteroot . '.temp/cache/' . $hostdir . '/' . $dir . '/' . md5 ( $hash ) . '.php';
	clearstatcache ();
	if (file_exists ( $file ) and filemtime ( $file ) + $exptime > time ()) {
		return unserialize ( substr ( file_get_contents ( $file ), strlen ( $http403 ) ) );
	} else {
		if (is_array ( $args )) {
			$content = call_user_func_array ( $func, $args );
		} else {
			$content = call_user_func_array ( $func, array () );
		}
		file_put_contents ( $file, $http403 . serialize ( $content ) );
		return $content;
	}
}
/**
 * 对类对象返回的结果进行散列缓存
 * 
 * 利用文件系统对类对象返回的结果进行保存并返回结果，下如果调用的函数和函数的
 * 参数一致，则直接从文件中返回结果。
 * 
 * @param object $obj 要缓存的对象 
 * @param string $method 缓存函数的参数
 * @param array $args 缓存函数的参数
 * @param int $exptime 缓存的时间(s秒)
 * @return mixed 缓存解码后的内容
 */
function readCacheFromObj($obj, $method, $args = array(), $exptime = 86400) {
	if (! is_object ( $obj )) {
		return null;
	}
	if (! is_array ( $args )) {
		$args = array ();
	}
	return call_user_func_array ( 'readCache', array ('call_user_func_array', array (array (&$obj, $method ), $args ), $exptime ) );
}
/**
 * 对函数返回的结果进行散列缓存更新
 * 
 * 利用文件系统对函数返回的结果进行保存。
 * 
 * @param string $func 生成缓存的函数
 * @param array $argv 缓存函数的参数
 * @return int 生成缓存的大小
 */
function writeCache($func, $args = array()) {
	global $flibcfg;
	$hash = serialize ( $func . serialize ( $args ) );
	$dir = '0x' . dechex ( sprintf ( "%u", crc32 ( $hash ) ) % 0xFF );
	$siteroot = getSiteCurrent ( true );
	$hostdir = $flibcfg ['HOST'] . '_' . ($flibcfg ['PORT'] ? $flibcfg ['PORT'] : 80);
	$http403 = '<?php' . PHP_EOL . ' die("HTTP 403");?>';
	touchdir ( $siteroot . '.temp' );
	touchdir ( $siteroot . '.temp/cache' );
	touchdir ( $siteroot . '.temp/cache/' . $hostdir );
	touchdir ( $siteroot . '.temp/cache/' . $hostdir . '/' . $dir );
	$file = $siteroot . '.temp/cache/' . $hostdir . '/' . $dir . '/' . md5 ( $hash ) . '.php';
	if (is_array ( $args )) {
		$content = call_user_func_array ( $func, $args );
	} else {
		$content = call_user_func_array ( $func, array () );
	}
	return file_put_contents ( $file, $http403 . serialize ( $content ) );
}
/**
 * 对类对象返回的结果进行散列缓存更新
 * 
 * 利用文件系统对类对象返回的结果进行保存。
 *
 * @param object $obj 要缓存的对象
 * @param string $method  生成缓存的方法
 * @param array $args 缓存函数的参数
 * @return int 生成缓存的大小
 */
function writeCacheFromObj($obj, $method, $args = array()) {
	if (! is_object ( $obj )) {
		return null;
	}
	if (! is_array ( $args )) {
		$args = array ();
	}
	return strlen ( call_user_func_array ( 'writeCache', array ('call_user_func_array', array (array (&$obj, $method ), $args ) ) ) );
}
/**
 * 根据字段值数组创建可用于wml,web的隐藏字段
 * 
 * 默认生成wml格式
 *
 * @param bool $isweb 生成何种形式的hash默认为wml
 * @param array $skip 要跳过的字段
 * @return string 生成的隐藏表单
 */
function formfield($fields = null, $isweb = false, $skip = array()) {
	global $flibcfg;
	if (! $isweb) {
		$idTemplate = '<postfield name="%s" value="%s" />';
	} else {
		$idTemplate = '<input type="hidden" name="%s" value="%s" ' . $flibcfg ['tagclose'] . '>';
	}
	if ($fields == null && defined ( 'SID' )) {
		$fields = SID;
	} elseif (is_array ( $fields )) {
		$fields = strtr ( http_build_query ( $fields ), array ('&amp;' => '&' ) );
	}
	$fieldarr = explode ( '&', $fields );
	$returnValue = '';
	foreach ( $fieldarr as $v ) {
		if (in_array ( substr ( $v, 0, strpos ( $v, '=' ) ), $skip )) {
			continue;
		}
		$sid = explode ( '=', $v );
		if ($sid [0] === '') {
			continue;
		}
		$returnValue .= sprintf ( $idTemplate, $sid [0], $sid [1] );
	}
	return '-->' . $returnValue . '<!--';
}
/**
 * 将汉字等转成HTML实体,例如 汉->&#xxxx
 *
 * @param String $str 包含汉字等字符串
 * @param String $charset 字符编码
 * @return 将所有非ansi字符转成HTML实体
 */
function charTounicode($str, $charset = null) {
	global $flibcfg;
	if ($charset === null) {
		$charset = $flibcfg ['charset'];
	}
	if (function_exists ( 'mb_convert_encoding' )) {
		return call_user_func_array ( 'mb_convert_encoding', array ($str, 'HTML-ENTITIES', $charset ) );
	}
	return $str;
}
/**
 * 将HTML实体等转成汉字,例如 &#xxxx->汉
 *
 * @param String $str 包含HTML实体等字符串
 * @return 将所有HTML实体转成ansi字符
 */
function unicodeTochar($str) {
	if (extension_loaded ( 'mbstring' )) {
		global $flibcfg;
		return call_user_func_array ( 'mb_convert_encoding', array ($str, $flibcfg ['charset'], 'HTML-ENTITIES' ) );
	}
	return preg_replace_callback ( "|&#([x0-9])([0-9a-f]{2,5});|", "utf_8Tochar_callback", $str );
}
/**
 * 将HTML实体等转成汉字,例如 &#xxxx->汉,回调涵数，不直接调用
 *
 * @param Strng $str 包含汉字等字符串
 * @return 将所有HTML实体转成ansi字符
 */
function utf_8Tochar_callback($str) {
	if ($str [1] == "x") {
		$dec = hexdec ( $str [2] );
	} else {
		$dec = $str [1] . $str [2];
	}
	if ($dec < 128) {
		$utf = chr ( $dec );
	} elseif ($dec < 2048) {
		$utf = chr ( 192 + (($dec - ($dec % 64)) / 64) );
		$utf .= chr ( 128 + ($dec % 64) );
	} else {
		$utf = chr ( 224 + (($dec - ($dec % 4096)) / 4096) );
		$utf .= chr ( 128 + ((($dec % 4096) - ($dec % 64)) / 64) );
		$utf .= chr ( 128 + ($dec % 64) );
	}
	global $flibcfg;
	return iconv ( "utf-8", $flibcfg ['charset'], $utf );
}
/**
 * 将一段文字进行分页
 * 
 * 本函数不考虑多个标签嵌套的情况。主要用于
 * wml分页
 *
 * @param string $string 文字
 * @param int $currentpage 当前页数
 * @param int $num 每页文字数 
 * @param string $charset 编码
 * @return string 分页后的文字
 */
function truncateChartoPage($string, $currentpage = 1, $num = 500, $charset = null) {
	global $flibcfg;
	if ($charset === null) {
		$charset = $flibcfg ['charset'];
	}
	if (extension_loaded ( 'mbstring' )) {
		$strlen = mb_strlen ( $string, $charset );
		$offset = min ( max ( 0, ($currentpage - 1) * $num ), $strlen );
		return array ('HTML' => mb_substr ( $string, $offset, $num, $charset ), 'strlen' => strlen ( $string ) );
	} else {
		return array ('HTML' => $string, 'strlen' => strlen ( $string ) );
	}
}
/**
 * 将一段文字进行截取
 * 
 * @param string $string HTML文字
 * @param int $length 文字数 
 * @param string $etc 省略标记
 * @param bool $middle 是否截取两端的部分
 * @param string $charset 编码
 * @return string 截取到的文字
 */
function truncateChar($string, $length = 80, $etc = '...', $middle = false, $charset = null) {
	global $flibcfg;
	if ($charset === null) {
		$charset = $flibcfg ['charset'];
	}
	if (extension_loaded ( 'mbstring' )) {
		$strlen = mb_strlen ( $string, $charset );
		if ($strlen > $length) {
			$length -= min ( $length, strlen ( $etc ) );
			if (! $middle) {
				$string = mb_substr ( $string, 0, floor ( $length ), $charset ) . $etc;
			} else {
				$string = mb_substr ( $string, 0, ceil ( $length / 2 ), $charset ) . $etc . mb_substr ( $string, - floor ( $length / 2 ), $length - ceil ( $length / 2 ), $charset );
			}
		}
		return $string;
	} else {
		return $string;
	}
}
/**
 * 返回站点根目录
 * 
 * 在同一空间内建立多个域名站点时，本函数可以直接返回
 * 站点根目录。返回完整目录一般用于文件操作。而短目录
 * 可以用于站点上的文件路径。比较说图片路径.
 *
 * @param bool $fullpath 返回完整路径
 * @return string
 */
function getSiteCurrent($fullpath = false) {
	$path = '';
	if ($fullpath) {
		if (defined ( '__SITE__' )) {
			$path .= __SITE__;
		}
	}
	if (defined ( '__SITECURRENT__' )) {
		$path .= __SITECURRENT__ . '/';
	}
	return $path;
}